/*
 * 	Copyright 2004-2007 Lookstone Technologies
 *	Written by Jason Seeley
 * 
 *	This file and other files in Lookstone.Common may be freely used, 
 *	modified, and distributed so long as this block remains intact 
 *  in each file it appears in.
 * 
 *	Lookstone Technologies does not warrant that any of this source code 
 *	is free from defect, and will not accept responsibility for any 
 *  failure of software using this library.  By using this library, 
 *  you agree to that Lookstone Technologies and the author of this file 
 *	are not liable for any damages or injuries caused through the use
 *	of this library.
 */

using System;
using System.Collections.Generic;
using System.Text;

namespace Lookstone.Data.SQLite
{
	public abstract class SQLiteKeyBase<T> : SQLiteBase
	{
		private T _id;

		/// <summary>
		/// Default constructor for a new record
		/// </summary>
		public SQLiteKeyBase()
			: base() { _id = NewRecordID; }

		/// <summary>
		/// Constructor that attempts to load the object using the passed in 
		/// database connection
		/// </summary>
		/// <param name="context">Database connection context to use</param>
		/// <param name="id">ID of object to load</param>
		public SQLiteKeyBase(SQLiteConnectionContext context, T id)
		{
			_id = id;

			// Will reset _id to default(T) if load fails
			if (!_id.Equals(NewRecordID))
				Load(context);
		}

		/// <summary>
		/// Constructor that populates the record from the RowReader
		/// </summary>
		/// <param name="reader">RowReader containing data appropriate to this object</param>
		public SQLiteKeyBase(RowReader reader)
			: base(reader) { }

		#region /****** Properties ******/
		/// <summary>
		/// Gets the Key value of the record
		/// </summary>
		public virtual T ID
		{
			get { return InternalID; }
			set { }
		}

		/// <summary>
		/// Gets the value of a new record ID	
		/// </summary>
		protected virtual T NewRecordID
		{
			get { return default(T); }
		}

		/// <summary>
		/// Override to provide better information at derived levels
		/// </summary>
		public override bool IsNewRecord
		{
			get { return base.IsNewRecord; }
			set
			{
				base.IsNewRecord = value;
				if (base.IsNewRecord)
					_id = NewRecordID;
			}
		}

		/// <summary>
		/// Gets and sets the generic type ID. Derived classes will have a 
		/// public ID property
		/// </summary>
		protected T InternalID
		{
			get { return _id; }
			set { _id = value; }
		}
		#endregion /****** Properties ******/

		public override bool Equals(object obj)
		{
			if (obj == null)
				return false;

			if (this.GetType() == obj.GetType())
			{
				SQLiteKeyBase<T> keyBase = obj as SQLiteKeyBase<T>;

				// If the ID is 0 on both objects, it will usually not be equivalent; perform 
				// reference comparison
				if (this.IsNewRecord && keyBase.IsNewRecord)
					return object.ReferenceEquals(this, keyBase);

				// On saved objects, items are equivalent if the ID is the same
				return this.InternalID.Equals(keyBase.InternalID);
			}

			return base.Equals(obj);
		}

		public static bool Equals(SQLiteKeyBase<T> lhs, SQLiteKeyBase<T> rhs)
		{
			if (lhs == null && rhs == null)
				return true;

			return (lhs != null && lhs.Equals(rhs));
		}

		public void ResetToNewRecord()
		{
			_id = NewRecordID;
			IsNewRecord = true;
		}

		protected override void Load(SQLiteConnectionContext context)
		{
			base.Load(context);
			if (IsNewRecord)
				_id = NewRecordID;
		}

		public override int GetHashCode()
		{
			return ID.GetHashCode();
		}
	}
}
